#pragma once

#include <iostream>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <signal.h>
#include <cstring>
using namespace std;

#include "Log.hpp"
#include "ThreadPool.hpp"
#include "Task.hpp"
#include "Daemon.hpp"

#define DEFAULT_FD -1
#define DEFAULT_PORT 8080
#define DEFAULT_IP "0.0.0.0"

const int backlog = 10;
extern Log log;

enum{
    SOCKET_ERR = 1,
    SOCKET_BIND_ERR,
    LISTEN_ERR,
    ACCEPT_ERR,
};

class TcpServer;

class ThreadData
{
public:
    ThreadData(int sockfd, const string& clientip, const uint16_t& clientport, TcpServer* server)
        :_sockfd(sockfd), _clientip(clientip), _clientport(clientport), _server(server)
    {}

    int _sockfd;
    std::string _clientip;
    uint16_t _clientport;
    TcpServer* _server;
};



class TcpServer
{
public:
    TcpServer(uint16_t port = DEFAULT_PORT, string ip = DEFAULT_IP)
        :_listen_sockfd(DEFAULT_FD), _port(port), _ip(ip)
    {}

    void InitServer()
    {
        _listen_sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if(_listen_sockfd < 0)
        {
            log(Fatal, "_listen_sockfd create error, errno: %d, errstring: %s", errno, strerror(errno));
            exit(SOCKET_ERR);
        }
        log(Info, "_listen_sockfd create success, _listen_sockfd: %d", _listen_sockfd);    
       
        int opt = 1;
        setsockopt(_listen_sockfd, SOL_SOCKET, SO_REUSEADDR|SO_REUSEPORT, &opt, sizeof(opt));   //防止偶发性的服务器无法立即重启

        // 设置本地套接字信息
        struct sockaddr_in local;     
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        inet_aton(_ip.c_str(), &local.sin_addr);


        // 绑定
        if(bind(_listen_sockfd, (struct sockaddr*)&local, (socklen_t)sizeof(local)) < 0)
        {
            log(Fatal, "bind error, errno: %d, errstring: %s", errno, strerror(errno));
            exit(SOCKET_BIND_ERR);
        }

        // TCP是面向连接的，服务器会一直处于等待客户端连接的状态
        if(listen(_listen_sockfd, backlog) < 0)
        {
            log(Fatal, "listen error, errno: %d, errstring: %s", errno, strerror(errno));
            exit(LISTEN_ERR);
        }
    }

    // static void* Routine(void* args)
    // {
    //     pthread_detach(pthread_self());     // 线程分离
    //     ThreadData* td = static_cast<ThreadData*>(args);
    //     td->_server->Service(td->_sockfd, td->_clientip, td->_clientport);
    //     delete td;
    //     return nullptr;
    // }

    void Start()
    {   
        log.Enable(Classfile);      // 文件日志
        Daemon();   // 进程守护化

        ThreadPool<Task>::GetInstance()->Start();   // 服务启动同时也启动线程池

        // signal(SIGCHLD, SIG_IGN);   // 直接忽略子进程的退出

        log(Info, "TcpServer is running...");    
        while(true)
        {
            // 1. 获取新链接
            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            int sockfd = accept(_listen_sockfd, (struct sockaddr*)&client, &len);
            if(sockfd < 0)
            {
                log(Warning, "accept error, errno: %d, errstring: %s", errno, strerror(errno));
                continue;
            }
            uint16_t clientport = ntohs(client.sin_port);
            char clientip[32];
            inet_ntop(AF_INET, &client.sin_addr, clientip, sizeof(clientip));
            
            // 2. 通过新链接通信
            log(Info, "get a new link..., sockfd: %d, clientip: %s, clientport: %d", sockfd, clientip, clientport);    

            // version1 --- 单进程版
            // Service(sockfd, clientip, clientport);
            // close(sockfd);


            // version2 --- 多进程版（创建成本高）
            // pid_t id = fork();
            // if(id == 0)
            // {
            //     // child
            //     close(_listen_sockfd);      // child继承的，但是对于child而言，它是不必要的
            //     if(fork() > 0) exit(0);     // child 创建 child，然后自己先退
            //     Service(sockfd, clientip, clientport);      // 孙子进程执行以下代码，由OS领养
            //     close(sockfd);
            //     exit(0);
            // }
            // // father
            // close(sockfd);  // child已经继承了一份sockfd，fahter可以直接关掉，避免存在多余的sockfd
            // int ret = waitpid(id, nullptr, 0);
            // (void)ret;
        

            // version3 --- 多线程版（线程永远不退，越来越多，不现实）
            // ThreadData* td = new ThreadData(sockfd, clientip, clientport, this);
            // pthread_t tid;
            // pthread_create(&tid, nullptr, Routine, td);


            // version4 --- 线程池版（把每次的连接当作一次任务，交给线程池处理，适用于短服务）
            Task task(sockfd, clientip, clientport);
            ThreadPool<Task>::GetInstance()->Push(task);       // 将任务push到线程池，然后继续循环获取新链接
        }
    }

    // void Service(int sockfd, const string& clientip, const uint16_t& clientport)
    // {
    //     char buffer[4096];
    //     while (true)
    //     {
    //         ssize_t n = read(sockfd, buffer, sizeof(buffer));   // tcp是面向字节流的，可以像读写文件一样读写网络
    //         if(n > 0)
    //         {
    //             buffer[n] = 0;
    //             cout << "[client]$ " << buffer << endl;
    //             string message = "tcpserver echo# ";
    //             message += buffer;
                
    //             write(sockfd, message.c_str(), message.size());
    //         }
    //         else if(n == 0)
    //         {
    //             log(Info, "%s:%d quit, server close sockfd: %d", clientip.c_str(), clientport, sockfd);    
    //             break;
    //         }
    //         else 
    //         {
    //             log(Error, "read error, sockfd: %d, clientip: %s, clientport: %d", sockfd, clientip.c_str(), clientport);
    //             break;
    //         }
    //     }
    // }

    ~TcpServer(){}
private:
    int _listen_sockfd;
    uint16_t _port;
    string _ip;
};
